﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StringMath
{
    public class MathString
    {
        public string Integer;
        public string Decimal;
        public bool negitive;
        public static int MaxPercision = 1000000;
        public MathString(string Integer, string Decimal)
        {
            this.Integer = Integer;
            this.Decimal = Decimal;
            Cleanup();
        }
        public MathString(string Integer, string Decimal, bool negitive)
        {
            this.Integer = Integer;
            this.Decimal = Decimal;
            this.negitive = negitive;
            Cleanup();
        }
        
        private static int CharToint(char c)
        {
            int output = (int)c - 48;
            return output;
        }

        public static MathString Parse(double input)
        {
            bool negitive = false;
            if (input < 0)
            {
                negitive = true;
                input = -input;
            }
            double intDouble = Math.Floor(input);
            double decDouble = input - intDouble;
            MathString output = new MathString(intDouble.ToString(), decDouble.ToString(), negitive);
            return output;
        }
        public static MathString Parse(int input)
        {
            bool negitive = false;
            if (input < 0)
            {
                negitive = true;
                input = -input;
            }
            string Integer = input.ToString();
            string Decimal = "0";
            MathString output = new MathString(Integer, Decimal, negitive);
            return output;
        }
        public static MathString Parse(string input)
        {
            bool negitive = false;
            MathString output;
            string[] strings = input.Split(".".ToCharArray());
            if (strings[0].Contains('-'))
            {
                negitive = true;
                strings[0] = strings[0].Replace("-", "");
            }
            if(strings.Length ==1)
            {
                output = new MathString(strings[0],"0");
            }
            else
            {
                output = new MathString(strings[0], strings[1]);
            }
            return output;
        }       
        private MathString MultiplyByTen(int power)
        {
            if (Math.Abs(power) > Decimal.Length)
                Decimal = Decimal.PadRight(Math.Abs(power), '0');
            if (Math.Abs(power) > Integer.Length)
                Integer = Integer.PadLeft(Math.Abs(power), '0');
            if (power > 0)
            {
                string dat = Decimal.Substring(0, power);
                string newdecimal = Decimal.Remove(0, power);
                string newint = Integer + dat;
                return new MathString(newint, newdecimal);
            }
            else if (power < 0)
            {
                string dat = Integer.Substring(Integer.Length + power, -power);
                string newdecimal = dat + Decimal;
                string newint = Integer.Remove(Integer.Length + power);
                return new MathString(newint, newdecimal);
            }
            return this;
        }
        private void Cleanup()
        {
            this.Decimal = this.Decimal.TrimEnd("0".ToCharArray());
            this.Integer = this.Integer.TrimStart("0".ToCharArray());
            if (this.Decimal.Length == 0)
                this.Decimal = "0";
            if (this.Integer.Length == 0)
                this.Integer = "0";
        }
        public override string ToString()
        {
            string output = string.Format("{0}.{1}", Integer, Decimal);
            if (negitive)
                output = "-" + output;
            return output;
        }
        #region Operators
        public static MathString operator -(MathString number1, MathString number2)
        {
            bool negitive = false;
            string outDecimal = "";
            string outInteger = "";
            int DecimalLength = 0;
            int IntegerLength = 0;
            int IntegerCarry = 0;
            int DecimalCarry = 0;

            if (number1.Decimal.Length >= number2.Decimal.Length)
                DecimalLength = number1.Decimal.Length;
            else
                DecimalLength = number2.Decimal.Length;

            if (number1.Integer.Length >= number2.Integer.Length)
                IntegerLength = number1.Integer.Length;
            else
                IntegerLength = number2.Integer.Length;


            string Mat1Dec = number1.Decimal.PadRight(DecimalLength, '0');
            string Mat2Dec = number2.Decimal.PadRight(DecimalLength, '0');
            string Mat1Int = number1.Integer.PadLeft(IntegerLength, '0');
            string Mat2Int = number2.Integer.PadLeft(IntegerLength, '0');

            for (int i = DecimalLength - 1; i >= 0; i--)
            {
                char Mat1c = Mat1Dec[i];
                char Mat2c = Mat2Dec[i];

                int Mat1i = int.Parse(Mat1c.ToString());
                int Mat2i = int.Parse(Mat2c.ToString());

                int q = Mat1i - Mat2i - DecimalCarry;
                DecimalCarry = 0;
                if (q < 0)
                {
                    DecimalCarry = 1;
                    q += 10;
                }
                outDecimal = q.ToString() + outDecimal;
            }



            for (int i = IntegerLength - 1; i >= 0; i--)
            {
                char Mat1c = Mat1Int[i];
                char Mat2c = Mat2Int[i];

                int Mat1i = int.Parse(Mat1c.ToString());
                int Mat2i = int.Parse(Mat2c.ToString());
                int q = Mat1i - Mat2i - IntegerCarry - DecimalCarry;
                IntegerCarry = 0;
                DecimalCarry = 0;
                if (q < 0 && i != 0)
                {
                    q += 10;
                    IntegerCarry = 1;
                }
                else if (q < 0 && i == 0)
                {
                    q = -q;
                    negitive = true;
                }
                outInteger = q.ToString() + outInteger;
            }
            if (IntegerCarry != 0)
                outInteger = IntegerCarry.ToString() + outInteger;
            return new MathString(outInteger, outDecimal, negitive);
        }
        public static MathString operator /(MathString TopNumber, MathString BottomNumber)
        {

            MathString Output = new MathString("0", "0");
            MathString Left = TopNumber;
            int PlacesMoved = BottomNumber.Integer.Length - TopNumber.Integer.Length + 1;
            while (Left.Integer != "0" || Left.Decimal != "0" && Output.Decimal.Length <= MaxPercision)
            {
                MathString thisOne = Left.MultiplyByTen(PlacesMoved);
                thisOne -= BottomNumber;
                int count = 0;
                while (!thisOne.negitive)
                {
                    thisOne -= BottomNumber;
                    count++;
                }
                MathString thisnum = new MathString(count.ToString(), "0");
                thisnum = thisnum.MultiplyByTen( -PlacesMoved);
                Output += thisnum;

                Left -= (BottomNumber * thisnum);
                PlacesMoved++;
            }
            return Output;
        }
        public static MathString operator *(MathString number1, MathString number2)
        {
            MathString output = new MathString("0", "0");
            string Num1Num = number1.Integer + number1.Decimal;
            string Num2Num = number2.Integer + number2.Decimal;
            for (int i = Num2Num.Length - 1; i >= 0; i--)
            {
                for (int j = Num1Num.Length - 1; j >= 0; j--)
                {
                    int Num1i = CharToint(Num1Num[j]);
                    int Num2i = CharToint(Num2Num[i]);
                    int thisProduct = Num1i * Num2i;
                    MathString thisProductMat = MathString.Parse(thisProduct);
                    thisProductMat = thisProductMat.MultiplyByTen((Num1Num.Length - 1 - j) + (Num2Num.Length - 1 - i));
                    output += thisProductMat;
                }
            }
            output = output.MultiplyByTen( -(number1.Decimal.Length + number2.Decimal.Length));
            return output;
        }
        public static MathString operator ^(MathString Base, int Exponent)
        {
            MathString output = new MathString("1", "0");
            bool neg = false;
            if (Exponent < 0)
            {
                Exponent = -Exponent;
                neg = true;
            }
            for (int i = 0; i < Exponent; i++)
            {
                output = output * Base;
            }

            if (neg)
            {
                output = new MathString("1", "0") / output;
            }
            return output;
        }
        public static MathString operator +(MathString number1, MathString number2)
        {

            string outDecimal = "";
            string outInteger = "";
            int DecimalLength = 0;
            int IntegerLength = 0;
            int IntegerCarry = 0;
            int DecimalCarry = 0;

            if (number1.Decimal.Length >= number2.Decimal.Length)
                DecimalLength = number1.Decimal.Length;
            else
                DecimalLength = number2.Decimal.Length;

            if (number1.Integer.Length >= number2.Integer.Length)
                IntegerLength = number1.Integer.Length;
            else
                IntegerLength = number2.Integer.Length;


            string Mat1Dec = number1.Decimal.PadRight(DecimalLength, '0');
            string Mat2Dec = number2.Decimal.PadRight(DecimalLength, '0');
            string Mat1Int = number1.Integer.PadLeft(IntegerLength, '0');
            string Mat2Int = number2.Integer.PadLeft(IntegerLength, '0');

            for (int i = DecimalLength - 1; i >= 0; i--)
            {
                int Mat1i = CharToint(Mat1Dec[i]);
                int Mat2i = CharToint(Mat2Dec[i]);

                int q = Mat1i + Mat2i + DecimalCarry;
                DecimalCarry = 0;
                if (q >= 10)
                {
                    DecimalCarry = 1;
                    q -= 10;
                }
                outDecimal = q.ToString() + outDecimal;
            }

            for (int i = IntegerLength - 1; i >= 0; i--)
            {
                int Mat1i = CharToint(Mat1Int[i]);
                int Mat2i = CharToint(Mat2Int[i]);

                int q = Mat1i + Mat2i + IntegerCarry + DecimalCarry;
                IntegerCarry = 0;
                DecimalCarry = 0;
                if (q >= 10)
                {
                    IntegerCarry = 1;
                    q -= 10;
                }
                outInteger = q.ToString() + outInteger;
            }
            if (IntegerCarry != 0)
                outInteger = IntegerCarry.ToString() + outInteger;
            return new MathString(outInteger, outDecimal);
        }
        #endregion
    }
}
